package com.onerway.api.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.onerway.api.OnerWayClient;
import com.onerway.common.Signable;
import com.onerway.config.OnerWayConfig;
import com.onerway.entity.OnerWayPage;
import com.onerway.entity.OnerWayResponse;
import com.onerway.entity.charge.ChargeBack;
import com.onerway.entity.charge.ChargebackInfo;
import com.onerway.entity.payment.PaymentRes;
import com.onerway.entity.payment.TxnOrder;
import com.onerway.entity.payment.TxnOrderMsg;
import com.onerway.entity.payment.UpdateOrder;
import com.onerway.entity.refund.RefundReq;
import com.onerway.entity.settle.SettlementFile;
import com.onerway.entity.token.BindTokenInfo;
import com.onerway.entity.token.TokenReq;
import com.onerway.entity.transaction.QueryTransaction;
import com.onerway.entity.transaction.TransactionRecord;
import com.onerway.enums.EndpointEnum;
import com.onerway.enums.ProductTypeEnum;
import com.onerway.enums.SubProductTypeEnum;
import com.onerway.enums.TxnTypeEnum;
import com.onerway.util.SignUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.IOException;

public class OnerWayClientImpl implements OnerWayClient {

    private final OnerWayConfig onerWayConfig;

    private final TransactionHelper transactionHelper;

    public OnerWayClientImpl(OnerWayConfig onerWayConfig) {
        this.onerWayConfig = onerWayConfig;
        this.transactionHelper = new TransactionHelper(onerWayConfig);
    }

    @Override
    public OnerWayResponse<PaymentRes> cashierPayment(TxnOrder txnOrder) throws IOException {
        TxnOrderInner txnOrderInner = copy(txnOrder);

        return transactionHelper.doTransaction(txnOrderInner, EndpointEnum.CASHIER_PAYMENT, new TypeReference<OnerWayResponse<PaymentRes>>() {
        });
    }

    public OnerWayResponse<PaymentRes> payment(TxnOrder txnOrder) throws IOException {
        TxnOrderInner txnOrderInner = copy(txnOrder);

        return transactionHelper.doTransaction(txnOrderInner, EndpointEnum.PAYMENT, new TypeReference<OnerWayResponse<PaymentRes>>() {
        });
    }

    @Override
    public OnerWayResponse<PaymentRes> biPayment(TxnOrder txnOrder) throws IOException {
        TxnOrderInner txnOrderInner = copy(txnOrder);

        return transactionHelper.doTransaction(txnOrderInner, EndpointEnum.TXN_BI_PAYMENT, new TypeReference<OnerWayResponse<PaymentRes>>() {
        });
    }

    @Override
    public OnerWayResponse<PaymentRes> updatePayment(UpdateOrder updateOrder) throws IOException {
        return transactionHelper.doTransaction(updateOrder, EndpointEnum.UPDATE_PAYMENT, new TypeReference<OnerWayResponse<PaymentRes>>() {
        });
    }

    public OnerWayResponse<OnerWayPage<TransactionRecord>> txnList(QueryTransaction queryTransaction) throws IOException {
        return transactionHelper.doTransaction(queryTransaction, EndpointEnum.TXN_LIST, new TypeReference<OnerWayResponse<OnerWayPage<TransactionRecord>>>() {
        });
    }

    @Override
    public OnerWayResponse<OnerWayPage<ChargebackInfo>> chargebackList(ChargeBack chargeBack) throws IOException {
        return transactionHelper.doTransaction(chargeBack, EndpointEnum.TXN_LIST, new TypeReference<OnerWayResponse<OnerWayPage<ChargebackInfo>>>() {
        });
    }

    @Override
    public OnerWayResponse<String> onlineRefund(RefundReq refundReq) throws IOException {
        return transactionHelper.doTransaction(refundReq, EndpointEnum.TXN_REFUND, new TypeReference<OnerWayResponse<String>>() {
        });
    }

    @Override
    public OnerWayResponse<BindTokenInfo> tokenList(TokenReq tokenReq) throws IOException {
        return transactionHelper.doTransaction(tokenReq, EndpointEnum.TOKEN_LIST, new TypeReference<OnerWayResponse<BindTokenInfo>>() {
        });
    }

    @Override
    public byte[] settlementFileDownload(SettlementFile settlementFile) throws IOException {
        settlementFile.setSign(SignUtil.sign(settlementFile, onerWayConfig.getSecret()));
        return transactionHelper.download(settlementFile, EndpointEnum.SETTLEMENT_FILE_DOWNLOAD);
    }

    private static TxnOrderInner copy(TxnOrder txnOrder) {
        TxnOrderMsg txnOrderMsg = txnOrder.getTxnOrderMsg();
        TxnOrderMsgInner txnOrderMsgInner = new TxnOrderMsgInner();
        txnOrderMsgInner.setReturnUrl(txnOrderMsg.getReturnUrl());
        txnOrderMsgInner.setProducts(JSON.toJSONString(txnOrderMsg.getProducts()));
        txnOrderMsgInner.setTransactionIp(txnOrderMsg.getTransactionIp());
        txnOrderMsgInner.setAppId(txnOrderMsg.getAppId());
        txnOrderMsgInner.setJavaEnabled(txnOrderMsg.getJavaEnabled());
        txnOrderMsgInner.setColorDepth(txnOrderMsg.getColorDepth());
        txnOrderMsgInner.setScreenHeight(txnOrderMsg.getScreenHeight());
        txnOrderMsgInner.setScreenWidth(txnOrderMsg.getScreenWidth());
        txnOrderMsgInner.setTimeZoneOffset(txnOrderMsg.getTimeZoneOffset());
        txnOrderMsgInner.setAccept(txnOrderMsg.getAccept());
        txnOrderMsgInner.setUserAgent(txnOrderMsg.getUserAgent());
        txnOrderMsgInner.setContentLength(txnOrderMsg.getContentLength());
        txnOrderMsgInner.setLanguage(txnOrderMsg.getLanguage());
        txnOrderMsgInner.setPeriodValue(txnOrderMsg.getPeriodValue());
        txnOrderMsgInner.setNotifyUrl(txnOrderMsg.getNotifyUrl());

        TxnOrderInner txnOrderInner = new TxnOrderInner();
        txnOrderInner.setMerchantNo(txnOrder.getMerchantNo());
        txnOrderInner.setMerchantTxnId(txnOrder.getMerchantTxnId());
        txnOrderInner.setMerchantCustId(txnOrder.getMerchantCustId());
        txnOrderInner.setOrderAmount(txnOrder.getOrderAmount());
        txnOrderInner.setOrderCurrency(txnOrder.getOrderCurrency());
        txnOrderInner.setProductType(txnOrder.getProductType());
        txnOrderInner.setBillingInformation(JSON.toJSONString(txnOrder.getBillingInformation()));
        txnOrderInner.setShippingInformation(JSON.toJSONString(txnOrder.getShippingInformation()));
        txnOrderInner.setSubProductType(txnOrder.getSubProductType());
        txnOrderInner.setTxnOrderMsg(JSON.toJSONString(txnOrderMsgInner));
        txnOrderInner.setLpmsInfo(JSON.toJSONString(txnOrder.getLpmsInfo()));
        txnOrderInner.setTxnType(txnOrder.getTxnType());
        txnOrderInner.setCardInfo(JSON.toJSONString(txnOrder.getCardInfo()));
        txnOrderInner.setSign(txnOrder.getSign());

        return txnOrderInner;
    }

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    private static class TxnOrderInner implements Signable {

        /**
         * 商户号。由Onerway分配，在Onerway后台获取。
         */
        private String merchantNo;

        /**
         * 顾客每次付款的订单号，必须保证单号唯一。
         */
        private String merchantTxnId;


        /**
         * 客户在商户的唯一标识。
         */
        private String merchantCustId;


        private String orderAmount;

        private String orderCurrency;

        private ProductTypeEnum productType;

        /**
         * 交易账单信息，除订阅复购外必填。 格式为 json 字符串。 请参阅对象 TransactionInformation
         */
        private String billingInformation;

        /**
         * 交易邮寄信息，除订阅复购外必填。 格式为 json 字符串。 请参阅对象 TransactionInformation
         */
        private String shippingInformation;

        private SubProductTypeEnum subProductType;

        private String txnOrderMsg;

        /**
         * 本地支付方式信息，productType 为 LPMS 时必填，格式为 json 字符串。 请参阅对象 LpmsInfo
         */
        private String lpmsInfo;

        private TxnTypeEnum txnType;

        private String cardInfo;

        private String sign;
    }


    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    private static class TxnOrderMsgInner {

        /**
         * 同步返回地址，顾客付款完成后，Onerway的托管页面会通过这个地址重定向回商家的指定页面。
         **/
        private String returnUrl;

        /**
         * 顾客购买的商品信息列表，请参考下方Products对象
         * List =》 String
         **/
        private String products;

        /**
         * 持卡人交易IP
         **/
        private String transactionIp;

        /**
         * 店铺ID，商家在Onerway入驻网站/应用程序时，会生成一个与该网站/应用程序的唯一ID。 该ID在Onerway后台获取。
         **/
        private String appId;

        /**
         * 持卡人浏览器是否开启java，获取方式：window.navigator.javaEnabled()
         **/
        private Boolean javaEnabled;

        /**
         * 持卡人屏幕色深，获取方式：window.screen.colorDepth
         **/
        private String colorDepth;

        /**
         * 持卡人的屏幕分辨率，获取方式：window.screen.height
         **/
        private String screenHeight;

        /**
         * 持卡人的屏幕分辨率，获取方式：window.screen.width
         **/
        private String screenWidth;

        /**
         * 持卡人浏览器的时区，获取方式：((new Date()).getTimezoneOffset()).toString()
         **/
        private String timeZoneOffset;

        /**
         * 持卡人浏览器的 Accept 请求头
         **/
        private String accept;

        /**
         * 持卡人的浏览器类型，获取方式：window.navigator.userAgent
         **/
        private String userAgent;

        /**
         * 持卡人浏览器内容长度头部以外的内容长度
         **/
        private String contentLength;

        /**
         * 持卡人浏览器的语言，获取方式：window.navigator.language
         **/
        private String language;

        /**
         * 分期付款期数。对应咨询分期期数接口返回的期数值。当 subProductType 为 INSTALLMENT 时必填。
         **/
        private String periodValue;

        /**
         * 通知地址。详见通知
         **/
        private String notifyUrl;


    }


}
